1 module project.gen; 2 import std.path:buildNormalizedPath; 3 import std.file; 4 import std.format:format; 5 import std.process; 6 import std.array:join,split,array; 7 8 struct TemplateInfo 9 { 10 string initMethod=q{ 11 }, 12 update="", 13 render=q{ 14 drawText("You can start using the D Scripting API Here!", 400, 300, 2.0, HipColor.white, 15 HipTextAlign.center 16 ); 17 }, 18 dispose=""; 19 } 20 21 struct DubProjectInfo 22 { 23 string author = "HipremeEngine"; 24 string projectName = "Hipreme Engine Test"; 25 string desc = "Hipreme Engine test scene"; 26 } 27 28 string generateCodeTemplate(TemplateInfo info = TemplateInfo()) 29 { 30 return format!q{ 31 module gamescript.entry; 32 import hip.api; 33 34 /** 35 * Call `dub` to generate the DLL, after that, just execute `dub -c run` for starting your project 36 */ 37 class MainScene : AScene, IHipPreloadable 38 { 39 mixin Preload; 40 41 /** Constructor */ 42 override void initialize() 43 { 44 %s 45 } 46 /** Called every frame */ 47 override void update(float dt) 48 { 49 %s 50 } 51 /** Renderer only, may not be called every frame */ 52 override void render() 53 { 54 %s 55 } 56 /** Pre destroy */ 57 override void dispose() 58 { 59 %s 60 } 61 override void onResize(uint width, uint height){} 62 } 63 64 mixin HipEngineMain!MainScene; 65 }(info.initMethod, info.update, info.render, info.dispose); 66 } 67 68 69 string escapeWindowsPathSep(string input) 70 { 71 string output = ""; 72 foreach(ch; input) 73 if(ch == '\\') 74 output~="\\\\"; 75 else 76 output~= ch; 77 return output; 78 } 79 80 string generateDubProject(DubProjectInfo info) 81 { 82 import std.conv; 83 import std.uni:toLower; 84 import std.algorithm:map; 85 dstring outputName = info.projectName.split(" ").join("_").array; 86 dstring name = outputName.map!(character => character.toLower).array; 87 88 return format!`{ 89 "$schema": "https://raw.githubusercontent.com/Pure-D/code-d/master/json-validation/dub.schema.json", 90 "authors": ["%s"], 91 "description" : "%s", 92 "license": "proprietary", 93 "targetName" : "%s", 94 "name" : "%s", 95 "engineModules": [ 96 "util", 97 "timer", 98 "tween", 99 "data", 100 "math", 101 "game2d" 102 ], 103 "stringImportPaths": ["#PROJECT/ct_assets"], 104 "dflags-ldc": ["--disable-verify", "--oq"], 105 "plugins": { 106 "getmodules": "#HIPREME_ENGINE/tools/internal/plugins/getmodules" 107 }, 108 "preBuildPlugins": { 109 "getmodules": ["#PROJECT/ct_assets/scriptmodules.txt"] 110 }, 111 "configurations": 112 [ 113 { 114 "name" : "script", 115 "targetType": "dynamicLibrary", 116 "dflags-ldc": ["-link-defaultlib-shared=true"], 117 "dependencies": { 118 "hipengine_api": {"path": "#HIPREME_ENGINE/api"} 119 }, 120 "lflags-windows-ldc": [ 121 "/WHOLEARCHIVE:hipengine_api_bindings", 122 "/WHOLEARCHIVE:hipengine_api_interfaces" 123 ], 124 "versions": ["ScriptAPI"], 125 "lflags-windows": ["/WX"] 126 }, 127 { 128 "name": "release", 129 "targetType": "executable", 130 "dependencies": { 131 "hipreme_engine": {"path": "#HIPREME_ENGINE"} 132 }, 133 "subConfigurations": { 134 "hipreme_engine": "desktop-release" 135 } 136 }, 137 { 138 "name": "release-wasm", 139 "targetType": "executable", 140 "dependencies": {"hipreme_engine": {"path": "#HIPREME_ENGINE"}}, 141 "subConfigurations": { 142 "hipreme_engine": "wasm", 143 "game2d": "direct" 144 } 145 }, 146 { 147 "name": "appleos", 148 "targetType": "staticLibrary", 149 "dependencies": {"hipreme_engine": {"path": "#HIPREME_ENGINE"}}, 150 "subConfigurations": {"hipreme_engine": "appleos", "game2d": "direct"} 151 }, 152 { 153 "name": "ios", 154 "targetType": "staticLibrary", 155 "dependencies": {"hipreme_engine": {"path": "#HIPREME_ENGINE"}}, 156 "subConfigurations": {"hipreme_engine": "ios", "game2d": "direct"} 157 }, 158 { 159 "name": "android", 160 "targetType": "dynamicLibrary", 161 "dependencies": { "hipreme_engine": {"path": "#HIPREME_ENGINE"} }, 162 "subConfigurations": {"hipreme_engine": "android", "game2d": "direct"} 163 }, 164 { 165 "name": "uwp", 166 "dflags-ldc": ["-link-defaultlib-shared=true"], 167 "targetType": "dynamicLibrary", 168 "dependencies": {"hipreme_engine": {"path": "#HIPREME_ENGINE"}}, 169 "subConfigurations": {"hipreme_engine": "uwp", "game2d": "direct"} 170 }, 171 { 172 "name": "psvita", 173 "targetType": "staticLibrary", 174 "subConfigurations": {"hipreme_engine": "psvita", "game2d": "direct"} 175 }, 176 { 177 "name": "run", 178 "targetType": "dynamicLibrary", 179 "lflags-windows": [ 180 "/WX" 181 ], 182 "postGenerateCommands-windows": ["cd /d #HIPREME_ENGINE && redub -c script -- $PACKAGE_DIR"], 183 "postGenerateCommands-linux": ["cd #HIPREME_ENGINE && redub -c script -- $PACKAGE_DIR"] 184 } 185 ] 186 } 187 `(info.author, info.desc, outputName, name); 188 } 189 190 string generateReadmeContent(string projectName) 191 { 192 return "# "~projectName~"\n"~projectName~" is made using Hipreme Engine.\n" ~ 193 "## Building Instructions \n" ~ 194 "1. Run `dub hipreme_engine:hbuild`\n" ~ 195 "2. Select 'Select Game'\n" ~ 196 "3. Select the folder containing "~projectName~"\n"~ 197 "4. Now you can simply choose the platform to build for"; 198 } 199 200 string generateVSCodeDebuggerLaunch(string enginePath) 201 { 202 import std.system; 203 string hipEnginePath = enginePath; 204 string hipEngineExecutable = (buildNormalizedPath(hipEnginePath, "bin", "desktop", "hipreme_engine") ~ ((os == OS.linux) ? "" : ".exe")).escapeWindowsPathSep; 205 return format!q{ 206 { 207 // Use IntelliSense to learn about possible attributes. 208 // Hover to view descriptions of existing attributes. 209 // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 210 // Auto Generated by HipremeEngine project generator. 211 // Automatically handle SIGUSR1 and SIGUSR2 as they are currently used in semaphore.wait 212 "version": "0.2.0", 213 "configurations": [ 214 { 215 "name": "Debug", 216 "type": "gdb", 217 "request": "launch", 218 "target": "%s", 219 "cwd": "${workspaceRoot}", 220 "arguments": "${workspaceRoot}", 221 "debugger_args": [ 222 "-ex", "handle SIGUSR1 noprint", 223 "-ex", "handle SIGUSR2 noprint" 224 ] 225 } 226 ] 227 } 228 }(hipEngineExecutable); 229 } 230 231 import commons; 232 bool generateProject(ref Terminal t, string projectPath, string enginePath, 233 DubProjectInfo dubInfo, TemplateInfo templateInfo) 234 { 235 string dubProj = generateDubProject(dubInfo); 236 string codeTemplate = generateCodeTemplate(templateInfo); 237 string debugLauncher = generateVSCodeDebuggerLaunch(enginePath); 238 239 try 240 { 241 //Project folder 242 t.writeln("Creating project folder"); 243 mkdirRecurse(projectPath); 244 //Source Folder 245 t.writeln("Creating scripts folder"); 246 mkdirRecurse(buildNormalizedPath(projectPath, "source", "gamescript")); 247 //Assets Folder 248 t.writeln("Creating assets folder"); 249 mkdirRecurse(buildNormalizedPath(projectPath, "assets")); 250 //Compilation Time Assets folder 251 t.writeln("Creating Compilation Time Assets folder"); 252 mkdirRecurse(buildNormalizedPath(projectPath, "ct_assets")); 253 //VSCode Folder 254 t.writeln("Creating vscode folder"); 255 mkdirRecurse(buildNormalizedPath(projectPath, ".vscode")); 256 257 t.writeln("Writing code template for gamescript/entry.d"); 258 std.file.write(buildNormalizedPath(projectPath, "source", "gamescript", "entry.d"), codeTemplate); 259 t.writeln("Writing dub.template.json"); 260 std.file.write(buildNormalizedPath(projectPath, "dub.template.json"), dubProj); 261 t.writeln("Writing README.md"); 262 std.file.write(buildNormalizedPath(projectPath, "README.md"), generateReadmeContent(dubInfo.projectName)); 263 t.writeln("Writing VSCode debug launcher"); 264 std.file.write(buildNormalizedPath(projectPath, ".vscode", "launch.json"), debugLauncher); 265 266 t.writeln("Writing .gitignore"); 267 std.file.write(buildNormalizedPath(projectPath, ".gitignore"), q{ 268 dub.selections.json 269 dub.json 270 .DS_Store 271 .dub 272 .history 273 .vs 274 bin 275 *.exe 276 *.exp 277 *.lnk 278 *.dll 279 *.dll_hiptempdll 280 *.so 281 *.lib 282 *.a 283 *.pdb 284 }); 285 } 286 catch(Exception e) 287 { 288 t.writelnError(e.toString); 289 return false; 290 } 291 import commons; 292 return writeTemplate(t, projectPath, enginePath); 293 }